import events from "events";
import { checkOptions } from "../common";
import { LayerController } from "../LayerController/index";
import { v4 as uuidv4 } from 'uuid';

export class BasicThematicLayer extends events.EventEmitter {
  protected map: any;
  protected container: HTMLElement | string | undefined; // 卡片容器
  protected viewMap: Map<string, any>; // 面板实例vue
  private LayerController: any; // 图层控制器
  private sourceList: Set<string> = new Set();

  constructor(options: any) {
    super();

    // 校验入参
    const checkedOptions = checkOptions(options, [
      { key: "map", require: true },
      // { key: "container", require: true },
    ]);
    this.map = checkedOptions.map;
    this.viewMap = new Map();
    // this.container = checkedOptions.container;
    this.LayerController = new LayerController(options);
  }

  /**
   * 抛出错误
   */
  private __throwError__(path: string, description: string) {
    let errorMsg = {
      msg: `${path} : ${description}`,
    }
    this.emit("commonError", { path, description })
    throw new Error(JSON.stringify(errorMsg));
  } 

  /**
   * 获取数据源
   * @param {string} sourceId 数据源ID 
   */
  public getSource(sourceId: string) {
    return this.map.getSource(sourceId);
  }

  /**
   * 添加数据源
   * @param {string} sourceId 数据源id
   * @param {object} source 数据源
   */
  public addSource(
    sourceId: string,
    source: {
      type: string;
      data?: any;
      url?: string;
      tiles?: any;
      maxzoom?: any;
      coordinates?: number[];
      clusteMaxZoom?: any;
      cluserRadius?: any;
      cluster?: any;
      scheme?: string;
    }
  ) {
    if (sourceId) {
      // 已存在图层，更新data
      if (this.getSource(sourceId)) {
        switch (source.type) {
          case "geojson":
            this.getSource(sourceId).setData(source.data);
            break;
          case "image":
            this.getSource(sourceId).updateImage(source);
            break;
          case "raster":
            this.getSource(sourceId).reload();
            break;
          case "canvas":
            this.getSource(sourceId).setCoordinates(source.coordinates);
            break;
        
          default:
            this.__throwError__("BasicThematicLayers => addSource", `addSource不存在${source.type}类型,更新失败`);
            break;
        } 
      } else {
        this.map.addSource(sourceId, source);
        this.sourceList.add(sourceId);
      }
    } else {
      this.__throwError__("BasicThematicLayer => addSource", "sourceId不能为空");
    }
  }

  /**
   * 移除数据源 如果传入了数据源ID，移除指定的数据源， 若果没传的话就移除所有数据源
   * @param {string} sourceId source源ID
   */
  public removeSource(sourceId?: string) {
    if (sourceId) {
      if (this.sourceList.has(sourceId)) {
        this.map.removeSource(sourceId);
        this.sourceList.delete(sourceId);
      } else {
        this.__throwError__("BasicThematicLayer => removeSource", `${sourceId}不存在，移除失败`);
      }
    } else {
      this.sourceList.forEach((id) => {
        this.map.removeSource(id);
        this.sourceList.clear();
      })
    }
  }

  /**
   * 添加图片
   * @param {Object[]} images 
   * @param {string} images.name
   * @param {string} iamges.url
   * @param {Function} callback
   */
  public addImages(images: {name: string, url: string}[], callback: Function) {
    this.LayerController.addImages(images)
      .then((imagePromises: any) => {
        callback.call(self, imagePromises);
        this.emit("addImages", imagePromises);
      })
      .catch((err: any) => {
        this.__throwError__("BasicThematicLayer => addImages", err)
      })
   }

  /**
   * 移除图片
   * @param {string[]} imageNames
   */
  public removeImages(imageNames: string[]) {
    if (Array.isArray(imageNames)) {
      imageNames.forEach((imageName: string) => {
        this.map.removeImage(imageName);
        this.emit("removeImage", imageName);
      })
    } else {
      this.__throwError__("BasicThematicLayer => removeImages", `入参错误，请检查入参${imageNames}`);
    }
  }

  /**
   * 添加单个或者多个图层事件
   * @param {object[]} mapEventList
   * @param {string} mapEventList.type
   * @param {layerId} mapEventList.layerId
   * @param {function} mapEventList.listener
   */
  public addLayerEvents(mapEventList: { type: string, layerId: string, listener: Function }[]) {
    if (Array.isArray(mapEventList)) {
      mapEventList.forEach(({ type, layerId, listener }) => {
        this.LayerController.addLayerEvent({
          type,
          layerId,
          listener: listener.bind(this),
        });
        this.emit("addLayerEvents", mapEventList);
      })
    } else {
      this.__throwError__("BasicThematicLayer => addLayerEvents", `入参错误，请检查入参${mapEventList}`)
    }
  }

  /**
   * 移除单个或者多个图层事件
   * @param {object[]} mapEventList
   * @param {string} type
   * @param {string} layerId
   */
  public removeLayerEvents(mapEventList: {
    type: string,
    layerId?: string,
  }[]) {
    if (Array.isArray(mapEventList)) {
      mapEventList.forEach(({ type, layerId }) => {
        this.LayerController.removeLayerEvent({
          type,
          layerId
        });
        this.emit("removeLayerEvents", mapEventList);
      })
    } else {
      this.__throwError__("BasicThematicLayer => removeLayerEvents", `入参错误，请检查入参${mapEventList}`);
    }
  }

  /**
   * 移除单个或者多个图层事件
   * @param {object[]} mapEventList
   * @param {string} type
   * @param {string} layerId
   */
  public clearLayerEvents(mapEventList: {
    type: string;
    layerId?: string;
  }[]) {
    if (Array.isArray(mapEventList)) {
      mapEventList.forEach(({ type, layerId }) => {
        if (layerId) {
          this.LayerController.clearLayerEvent({
            type,
            layerId,
          });
        } else {
          this.LayerController.clearLayerEvent({
            type,
          });
        }
        this.emit("clearLayerEvents", mapEventList);
      })
    } else {
      this.__throwError__("BasicThematicLayer => clearLayerEvents", `入参错误，请检查入参${mapEventList}`);
    }
  }

  /**
   * 添加单个或者多个图层
   * @param {object[]} layerDataList
   * @param {string} layerDataList.id
   * @param {string} layerDataList.type
   * @param {string} layerDataList.source
   * //或者以下配置，添加beforeId
   * @param {object[]} layerDataList
   * @param {string} layerDataList.layer
   * @param {string} layerDataList.beforeId  
   */
  public addLayers(layerDataList: Array<any>) {
    if (Array.isArray(layerDataList)) {
      layerDataList.forEach((layer) => {
        if (layer?.layer && layer?.beforeId) {
          this.LayerController.addLayer(layer?.layer, layer?.beforeId);
        } else {
          this.LayerController.addLayer(layer);
        }
      });
      this.emit("addLayers", layerDataList);
    } else {
      this.__throwError__("BasicThematicLayer => addLayers", `入参错误，请检查入参${layerDataList}`);
    }
  }

  /**
   * 移除单个或者多个图层
   * @param {string[]} layerIds
   */
  public removeLayers(layerIds: Array<string>) {
    if (Array.isArray(layerIds)) {
      this.LayerController.removeLayers(layerIds);
    } else {
      this.LayerController.removeAllLayers();
    }
    this.emit("removeLayers", layerIds);
  }

  /**
   * 显示单个或者多个图层
   * @param {Array<string>} layerIds 
   */
  public showLayers(layerIds?: Array<string>) {
    if (Array.isArray(layerIds) && layerIds.length > 0) {
      this.LayerController.showLayers(layerIds);
    } else {
      this.LayerController.showAllLayers();
    }
    this.emit("showLayers", layerIds);
  }


  /**
   * 隐藏单个或者多个图层
   * @param {Array<string>} layerIds
   */
  public hideLayers(layerIds?: Array<string>) {
    if (Array.isArray(layerIds) && layerIds.length > 0) {
      this.LayerController.hideLayers(layerIds);
    } else {
      this.LayerController.hideAllLayers();
    }
    this.emit("hideLayers", layerIds);
  }

  /**
   * 创建DOM
   * @param {object} component Vue实例
   * @description 返回的Vue中被注入__viewId，可通过__viewId访问和销毁实例
   * @returns component
   */
  public createComponent(component: any) {
    const id = uuidv4();
    // 创建容器
    const divDom = document.createElement("div");
    divDom.id = id;
    if (typeof this.container === 'string') {
      document.getElementById(this.container)?.appendChild(divDom);
    } else {
      this.container?.appendChild(divDom);
    }
    component.__viewId = id;
    component.$mount(divDom);
    this.viewMap && this.viewMap.set(id, component);
    this.emit("load", component);
    return component;
  }

  /**
   * 销毁DOM 为空则销毁所有面板
   * @param {string[]} viewIds
   */
  public removeComponents(viewIds: Array<string>) {
    if (Array.isArray(viewIds)) {
      viewIds.forEach((viewId) => {
        if (this.viewMap?.has(viewId)) {
          const component = this.viewMap.get(viewId);
          component.$el.remove();
          component.$destroy();
          this.viewMap.delete(viewId);
        }
      })
    } else {
      this.viewMap?.forEach((component) => {
        component.$el.remove();
        component.$destroy();
        if (this.container) {
          if (typeof this.container === "string") {
            let container = document.getElementById(this.container);
            container?.parentNode?.removeChild(container);
          } else {
            this.container.parentNode?.removeChild(this.container);
          }
        }
      });
      this.viewMap?.clear();
    }
    this.emit("removeComponents", viewIds);
  } 

  /**
   * 面板显示隐藏切换， 为空则隐藏所有
   * @param {string[]} viewIds 隐藏的 component id
   * @param {boolean} visible 是否隐藏
   */
  private __changeComponentVisible__(viewIds: Array<string>, visible: boolean) {
    // 指定viewIds
    if (Array.isArray(viewIds)) {
      viewIds.forEach((viewId) => {
        if (this.viewMap.has(viewId)) {
          const component = this.viewMap.get(viewId);
          component.$el.style.display = visible ? "" : "none";
        } else {
          this.__throwError__("basicComponent => __changeComponentVisible", `不存在${viewId}面板`);
        }
      });
    } else {
      // 全部
      this.viewMap.forEach((component) => {
        if (this.viewMap.get(component.__viewId)) {
          component.$el.style.display = visible ? "" : "none";
        } else {
          this.__throwError__("basicComponent => __changeComponentVisible", `不存在${component.__viewId}面板`);
        }
      })
    }
  }

  /**
   * 显示面板 为空则显示所有
   * @param {string[]} viewIds 需要显示的面板ids
   */
  public showComponents(viewIds?: Array<string>) {
    viewIds && this.__changeComponentVisible__(viewIds, true);
    this.emit("showComponent", {
      viewIds,
    });
  }

  /**
   * 隐藏面板 为空则隐藏所有面板
   * @param {string[]} viewIds 需要隐藏的面板ids
   */
  public hideComponents(viewIds?: Array<string>) {
    viewIds && this.__changeComponentVisible__(viewIds, false);
    this.emit("hideComponents", {
      viewIds,
    });
  }

  /**
   * 显示 面板和图层 为空则显示所有
   * @param {object} options 图层IDs 和 面板IDs
   * @param {string[]} options.layerIds 面板IDs
   * @param {string[]} options.viewIds 面板IDs
   */
  public show(options?: {
    layerIds?: Array<string>,
    viewIds?: Array<string>,
  }) {
    options && this.showLayers(options.layerIds);
    options && this.showComponents(options.viewIds);
  }

  /**
   * 隐藏 面板和图层 为空则隐藏所有
   * @param {object} options 图层IDs 和 面板IDs
   * @param {string[]} options.layerIds
   * @param {string[]} options.viewIds
   */
  public hide(options?: {
    layerIds?: Array<string>,
    viewIds?: Array<string>,
  }) {
    options && this.hideLayers(options.layerIds);
    options && this.hideComponents(options.viewIds);
  }

  /**
   * 销毁面板和图层 为空则销毁所有
   * @param {object} options 
   * @param {string[]} options.layerIds
   * @param {string[]} options.sourceIds
   * @param {string[]} options.viewIds
   */
  public close(options?: {
    layerIds?: Array<string>,
    sourceIds?: Array<string>,
    viewIds?: Array<string>,
  }) {
    options?.layerIds && this.removeLayers(options.layerIds);
    if (Array.isArray(options?.sourceIds)) {
      options?.sourceIds.forEach((sourceId) => {
        sourceId && this.removeSource(sourceId);
      })
    } else {
      this.removeSource();
    }
    options?.viewIds && this.removeComponents(options.viewIds);
    this.emit("close", options)
  }
}
